#include "Grass.h"

Grass::Grass()
: mGrassFX(0)
, errors(0)
{
	HR(D3DXCreateTextureFromFile( gd3dDevice, "Textures/grassfin0.dds", &mGrassTex));

	HR(D3DXCreateEffectFromFile( gd3dDevice
							, "TransformTex.fx"
							, 0, 0,
							D3DXSHADER_DEBUG
							, 0, &mGrassFX
							, &errors));
	if(errors)
		MessageBox(0, (char*)errors->GetBufferPointer(), 0, 0);
	
	// Create the grass FX from a .fx file.
	HR(D3DXCreateEffectFromFile(gd3dDevice, "grass.fx", 
		0, 0, 0, 0, &mGrassFX, &errors));
	if( errors )
		MessageBox(0, (char*)errors->GetBufferPointer(), 0, 0);

	// Obtain handles.
	mhGrassTech     = mGrassFX->GetTechniqueByName("GrassTech");
	mhGrassViewProj = mGrassFX->GetParameterByName(0, "gViewProj");
	mhGrassTex      = mGrassFX->GetParameterByName(0, "gTex");
	mhGrassTime     = mGrassFX->GetParameterByName(0, "gTime");
	mhGrassEyePosW  = mGrassFX->GetParameterByName(0, "gEyePosW");
	mhGrassDirToSunW= mGrassFX->GetParameterByName(0, "gDirToSunW");

	HR(mGrassFX->SetTechnique(mhGrassTech));
	mGrassFX->SetTexture(mhGrassTex, mGrassTex);

	D3DXVECTOR3 pos(0, 0, 0);
	D3DXVECTOR3 scale(1, 1, 1);
	int indexOffset = 0;
	BuildGrassBuffers(indexOffset, pos, scale);
}

Grass::~Grass()
{
	//ReleaseCOM(mGrassMesh);
	ReleaseCOM(mGrassTex);
	ReleaseCOM(mGrassFX);
}

void Grass::OnResetDevice()
{
	mGrassFX->OnResetDevice();
}

void Grass::OnLostDevice()
{
	mGrassFX->OnLostDevice();
}

void Grass::Draw(D3DXMATRIX &mView, D3DXMATRIX &mProj, D3DXVECTOR3 &cPos, float currentTime)
{
	UINT numPasses = 0;
	HR(mGrassFX->Begin(&numPasses, 0));

	HR(mGrassFX->SetValue(mhGrassEyePosW, cPos, sizeof(D3DXVECTOR3)));
	HR(mGrassFX->SetMatrix(mhGrassViewProj, &(mView*mProj)));
	HR(mGrassFX->SetFloat(mhGrassTime, currentTime));

	HR(mGrassFX->Begin(&numPasses, 0));
	HR(mGrassFX->BeginPass(0));

	// Draw to depth buffer only.
	HR(mGrassMesh->DrawSubset(0));

	HR(mGrassFX->EndPass());
	HR(mGrassFX->End());
}

void Grass::Update(float dt)
{

}

void Grass::BuildGrassBuffers(int& indexOffset, D3DXVECTOR3& worldPos, D3DXVECTOR3& scale)
{
	D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
	UINT numElems = 0;
	HR(GrassVertex::decl->GetDeclaration(elems, &numElems));

	HR(D3DXCreateMesh(2,4, D3DXMESH_MANAGED, elems, gd3dDevice, &mGrassMesh));

	GrassVertex* v = 0;
	WORD* k = 0;
	HR(mGrassMesh->LockVertexBuffer(0, (void**)&v));
	HR(mGrassMesh->LockIndexBuffer(0, (void**)&k));

	// Only top vertices have non-zero amplitudes: 
	// The bottom vertices are fixed to the ground.
	float amp = 0.5f;
	v[0] = GrassVertex(D3DXVECTOR3(-1.0f,-0.5f, 0.0f), D3DXVECTOR2(0.0f, 1.0f), 0.0f);
	v[1] = GrassVertex(D3DXVECTOR3(-1.0f, 0.5f, 0.0f), D3DXVECTOR2(0.0f, 0.0f), amp);
	v[2] = GrassVertex(D3DXVECTOR3( 1.0f, 0.5f, 0.0f), D3DXVECTOR2(1.0f, 0.0f), amp);
	v[3] = GrassVertex(D3DXVECTOR3( 1.0f,-0.5f, 0.0f), D3DXVECTOR2(1.0f, 1.0f), 0.0f);

	// Set indices of fin.
	k[0] = 0 + indexOffset;
	k[1] = 1 + indexOffset;
	k[2] = 2 + indexOffset;
	k[3] = 0 + indexOffset;
	k[4] = 2 + indexOffset;
	k[5] = 3 + indexOffset;

	// Offset the indices by four to have the indices index into
	// the next four elements of the vertex buffer for the next fin.
	indexOffset += 4;

	// Scale the fins and randomize green color intensity.
	for(int i = 0; i < 4; ++i)
	{
		v[i].pos.x *= scale.x;
		v[i].pos.y *= scale.y;
		v[i].pos.z *= scale.z;

		// Generate random offset color (mostly green).
		v[i].colorOffset = D3DXCOLOR(0.1f,0.2f,	0.1f, 0.0f);
	}

	// Add offset so that the bottom of fin touches the ground
	// when placed on terrain.  Otherwise, the fin's center point
	// will touch the ground and only half of the fin will show.
	float heightOver2 = (v[1].pos.y - v[0].pos.y) / 2;
	worldPos.y += heightOver2;

	// Set world center position for the quad.
	v[0].quadPos = worldPos;
	v[1].quadPos = worldPos;
	v[2].quadPos = worldPos;
	v[3].quadPos = worldPos;

	HR(mGrassMesh->UnlockVertexBuffer());
	HR(mGrassMesh->UnlockIndexBuffer());
}